/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

@import 'tensorboard/webapp/angular_material_theming';

/***********************************************************
 * VARIABLE FILE IS INLINED WITH GENRULE. DO NOT IMPORT IT.
 * Variable file declares values for $tb-primary, $tb-accent
 * and $tb-warn
 **********************************************************/

// Angular Material theme definition.

// Include non-theme styles for core.
@include mat-core();

// Value for `app-bar` property in $tb-background. Can specify an override in
// _variable.scss to specifically customize this value.
$tb-app-bar-color: mat-color($tb-primary, default) !default;

$tb-dark-primary: $tb-primary !default;
$tb-dark-accent: $tb-accent !default;
$tb-dark-warn: $tb-warn !default;
// Value for `app-bar` property in $tb-dark-background. Can specify an override
// in _variable.scss to specifically customize this value.
$tb-dark-app-bar-color: mat-color($tb-dark-primary, default) !default;

$tb-theme: mat-light-theme($tb-primary, $tb-accent, $tb-warn);

// Overriding mat-light-theme-foreground variables.
$tb-foreground: map_merge(
  $mat-light-theme-foreground,
  (
    text: mat-color($mat-gray, 900),
    secondary-text: mat-color($mat-gray, 700),
    disabled-text: mat-color($mat-gray, 600),
    // TB specific variable.
    border: #ebebeb,
    link: mat-color($mat-blue, 700),
    link-visited: mat-color($mat-purple, 700),
  )
);
$tb-background: map_merge(
  $mat-light-theme-background,
  (
    app-bar: $tb-app-bar-color,
    // Default is `map.get($grey-palette, 50)`.
    background: #fff,
  )
);

$tb-theme: map_merge(
  $tb-theme,
  (
    foreground: $tb-foreground,
    background: $tb-background,
  )
);

$tb-dark-theme: mat-dark-theme(
  $tb-dark-primary,
  $tb-dark-accent,
  $tb-dark-warn
);
$tb-dark-foreground: map_merge(
  map-get($tb-dark-theme, foreground),
  (
    border: #555,
    disabled-text: mat-color($mat-gray, 700),
    link: mat-color($mat-blue, 400),
    link-visited: mat-color($mat-purple, 300),
  )
);
$tb-dark-background: map_merge(
  map-get($tb-dark-theme, background),
  (
    app-bar: $tb-dark-app-bar-color,
  )
);
$tb-dark-theme: map_merge(
  $tb-dark-theme,
  (
    background: $tb-dark-background,
    foreground: $tb-dark-foreground,
  )
);

/**
 * Mixin to facilitate styling an Angular component for the dark mode.
 * For customization that uses theming object (tb-foreground or tb-background),
 * please refer to `tb-theme-foreground-prop` and `tb-theme-background-prop`.
 *
 * For a large amount of customization, instead of the *-prop API, prefer to use
 * this tb-dark-theme mixin.
 *
 * Example usage:
 *
 * div {
 *   color: red;
 *   background: blue;
 *   @include tb-dark-theme {
 *     background: purple;
 *   }
 * }
 */
@mixin tb-dark-theme {
  @each $selector in & {
    @at-root :host-context(body.dark-mode) #{$selector} {
      @content;
    }
  }
}

@mixin _interal-tb-theme-prop-color(
  $object-name,
  $foreground-or-background,
  $dark-foreground-or-background,
  $css-property,
  $dict-name,
  $css-value-prefix
) {
  $light-color: map-get($foreground-or-background, $dict-name);
  $dark-color: map-get($dark-foreground-or-background, $dict-name);

  @if (not $light-color) {
    @error "Name '#{$dict-name}' is not found in light #{$object-name}.";
  }
  @if (not $dark-color) {
    @error "Name '#{$dict-name}' is not found in dark #{$object-name}.";
  }

  #{$css-property}: $css-value-prefix $light-color;

  @include tb-dark-theme {
    #{$css-property}: $css-value-prefix $dark-color;
  }
}

/**
 * Styles an Angular component for a given CSS property using foreground theming
 * dictionary. This mixin also facilitates theming for the dark mode.
 *
 * Example usage:
 *
 * div {
 *   color: red;
 *   @include tb-theme-foreground-prop(border-left, border, 5px solid);
 *   // `tb-foreground` has the `border` key. Above generates:
 *   // div[ngcomponentweirdid] {
 *   //   border-left: 1px solid map_get($tb-foreground, border);
 *   // }
 *   // :host-context(body.dark-mode) div[ngcomponentweirdid] {
 *   //   border-left: 1px solid map_get($tb-dark-foreground, border);
 *   // }
 *   //
 *   // Third argument is optional. In the example below, `color` only takes
 *   // color value so it is not needed.
 *   @include tb-theme-foreground-prop(color, secondary-text);
 * }
 */
@mixin tb-theme-foreground-prop(
  $css-property,
  $dict-name,
  $css-value-prefix: null
) {
  @include _interal-tb-theme-prop-color(
    foreground,
    $tb-foreground,
    $tb-dark-foreground,
    $css-property,
    $dict-name,
    $css-value-prefix
  );
}

/**
 * Styles an Angular component for a given CSS property using background theming
 * dictionary. This mixin also facilitates theming for the dark mode.
 *
 * Example usage:
 *
 * div {
 *   color: red;
 *   @include tb-theme-background-prop(backgroud-color, background);
 *   // Above generates:
 *   // div[ngcomponentweirdid] {
 *   //   backgroud-color: map_get($tb-background, background);
 *   // }
 *   // :host-context(body.dark-mode) div[ngcomponentweirdid] {
 *   //   backgroud-color: map_get($tb-dark-background, background);
 *   // }
 * }
 */
@mixin tb-theme-background-prop(
  $css-property,
  $dict-name,
  $css-value-prefix: null
) {
  @include _interal-tb-theme-prop-color(
    background,
    $tb-background,
    $tb-dark-background,
    $css-property,
    $dict-name,
    $css-value-prefix
  );
}

// Apply themed style for the global stylesheet (styles.scss).
@mixin tb-global-themed-styles() {
  // Include all theme-styles for the components based on the current theme.
  @include angular-material-theme($tb-theme);

  body {
    // Prevents ngx-color-picker from creating a scrollbar and misposition.
    overflow: hidden;
  }

  // Prevent color-picker from briefly showing scrollbar when calculating its
  // position.
  .cdk-overlay-container {
    contain: strict;
  }

  a:not(.mat-button, .mat-icon-button) {
    color: map-get($tb-foreground, link);

    &:visited {
      color: map-get($tb-foreground, link-visited);
    }
  }

  // Cannot use `tb-dark-theme` as :host-context in the global stylesheet is
  // meaningless.
  body.dark-mode {
    background-color: map-get($tb-dark-background, background);

    a:not(.mat-button, .mat-icon-button) {
      color: map-get($tb-dark-foreground, link);

      &:visited {
        color: map-get($tb-dark-foreground, link-visited);
      }
    }

    @include angular-material-theme($tb-dark-theme);
  }
}
